Skip to content

feat(studio): compact latency duration format across experiments and intake - #632

Merged
rrhyne merged 6 commits into
mainfrom
studio-latency-duration-format/rrhyne
Jul 14, 2026
Merged

feat(studio): compact latency duration format across experiments and intake#632
rrhyne merged 6 commits into
mainfrom
studio-latency-duration-format/rrhyne

Conversation

@rrhyne

@rrhyne rrhyne commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Latency was rendered as long raw-millisecond numbers and formatted three different ways across the app. This consolidates all latency/duration rendering onto one shared formatter that produces compact segments:

  • 10m 12s 13ms
  • 12s 34ms
  • 34ms

Why

Before, three formatters coexisted:

  • Experiment surfaces (group list "Avg Latency", detail header, session/task table) inlined `${Math.round(ms)} ms` — long unscaled milliseconds.
  • Intake surfaces used formatDurationMs (ms/s/min, 2 decimals).

Changes

  • New web/packages/studio/src/util/duration.tsformatDuration(ms): renders highest non-zero unit down to lowest, drops leading/trailing zero units, keeps interior zeros (1h 0m 5s), supports hours, preserves sub-ms precision (0.34ms), returns for null/undefined.
  • intakeTelemetry.tsformatDurationMs now aliases formatDuration, so all six intake trace/span surfaces adopt the new format with zero call-site churn.
  • ExperimentGroupDataView, ExperimentDetailMetrics, ExperimentSessionsDataView — call formatDuration instead of inline millisecond strings.
  • SpanTriggerMeta.tsx — removed a .replace(/\s+/g,'') that would collapse the segmented format into 10m12s13ms.

Testing

  • New duration.test.ts — 10/10 pass (covers the examples above plus edges: hours, interior zeros, rounding, sub-ms, zero/negative).
  • ESLint clean on all touched files.
  • Typecheck: no new errors introduced (the SpanEvaluationContext errors in intakeTelemetry.ts are pre-existing on main from an SDK schema change, unrelated to this PR).

Out of scope

The Agent Monitor inference-logs table has its own route-local formatDuration (ms/s/min, 1 decimal); left untouched intentionally.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Enhancements
    • Improved duration and latency formatting across experiment metrics, sessions, and intake details by using a shared formatter for consistent, compact time units.
    • Experiment latency and “Avg Latency” now display human-readable durations with standardized handling for missing values.
    • Intake duration display no longer strips whitespace, reflecting the formatted output directly.
  • Tests
    • Added dedicated test coverage for the shared duration formatter and updated duration-related UI expectations.

…riments and intake

Latency was formatted three different ways: experiment surfaces inlined
`${Math.round(ms)} ms`, intake used `formatDurationMs` (ms/s/min, 2 decimals),
producing long millisecond numbers in the experiment group list, experiment
detail header, and session/task tables.

Add a shared `formatDuration` util that renders compact segments
(`10m 12s 13ms`, `12s 34ms`, `34ms`) — highest non-zero unit down to the lowest,
interior zeros kept, hours supported, sub-ms precision preserved. Point the
experiment surfaces at it and alias `formatDurationMs` to it so all intake
trace/span surfaces pick up the new format with no call-site churn. Drop the
whitespace-strip in SpanTriggerMeta that would collapse the segmented format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
@rrhyne
rrhyne requested review from a team as code owners July 10, 2026 14:01
@github-actions github-actions Bot added the feat label Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 74e71f44-f152-4412-863a-d758a7f6f055

📥 Commits

Reviewing files that changed from the base of the PR and between e9ccd7c and 6bcadc7.

📒 Files selected for processing (1)
  • web/packages/studio/src/util/intakeTelemetry.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/packages/studio/src/util/intakeTelemetry.ts

📝 Walkthrough

Walkthrough

A shared formatDurationMs utility now formats durations across common date utilities, telemetry, and experiment latency views. Telemetry preserves the shared formatter’s spacing, while experiment views use it for latency values. Tests cover units, precision, rounding, and empty values.

Changes

Duration Formatting

Layer / File(s) Summary
Shared duration formatter
web/packages/common/src/utils/date.ts, web/packages/common/src/utils/date.test.ts
Adds formatDurationMs, routes formatTimeInSeconds through it, and tests null handling, unit formatting, precision, rounding, and non-positive values.
Telemetry formatter integration
web/packages/studio/src/util/intakeTelemetry.ts, web/packages/studio/src/components/IntakeDetail/IntakeComponents/SpanTriggerMeta.tsx, web/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.test.tsx
Re-exports the shared formatter, preserves formatted duration whitespace, and updates the telemetry duration expectation.
Experiment latency displays
web/packages/studio/src/components/dataViews/ExperimentGroupDataView/index.tsx, web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx, web/packages/studio/src/routes/ExperimentDetailRoute/ExperimentDetailMetrics.tsx
Formats experiment latency values with formatDurationMs while retaining existing null and placeholder behavior.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: compact duration formatting across Studio experiments and intake.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch studio-latency-duration-format/rrhyne

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 23880/31011 77.0% 61.8%
Integration Tests 13811/29660 46.6% 19.6%

@walston walston left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to pushback, just don't want parallel solutions to the same problem sprinkled throughout the codebase.

Comment thread web/packages/studio/src/util/duration.ts Outdated
rrhyne and others added 2 commits July 10, 2026 15:40
…urationMs

Address review: formatTimeInSeconds already lived in @nemo/common/src/utils/date
and did the same segmented formatting. Instead of a parallel studio-local
formatDuration, add an ms-aware formatDurationMs primitive next to it and make
formatTimeInSeconds delegate to it, so there is a single segmentation
implementation. formatDurationMs drops zero-valued units (including interior
ones, e.g. `1h 5s`) to match formatTimeInSeconds, keeps sub-ms precision, and
adds an `ms` component (`10m 12s 13ms`, `12s 34ms`, `34ms`).

Repoint the experiment surfaces and intakeTelemetry's re-export at the common
helper and delete the studio-local util. formatTimeInSeconds behavior is
unchanged (verified by its existing tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
…ormat

The trace headline-metrics test asserted the old `12.23 s` format; the shared
formatDurationMs now renders `12s 230ms`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
Comment thread web/packages/studio/src/routes/ExperimentDetailRoute/ExperimentDetailMetrics.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
web/packages/common/src/utils/date.test.ts (1)

4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Relative import violates the no-relative-import-paths guideline.

from './date' is a relative import to a sibling file. As per path instructions, "Never use relative imports. Always use absolute alias paths ... even for sibling files in the same directory. ESLint enforces this with no-relative-import-paths."

♻️ Proposed fix
-import { formatDurationMs, formatTimeInSeconds, utcToLocalDate } from './date';
+import { formatDurationMs, formatTimeInSeconds, utcToLocalDate } from '`@nemo/common/src/utils/date`';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/packages/common/src/utils/date.test.ts` at line 4, Update the date
utility import in the test to use the repository’s configured absolute alias
path instead of the relative './date' path, while preserving the existing
imported symbols formatDurationMs, formatTimeInSeconds, and utcToLocalDate.

Source: Path instructions

web/packages/common/src/utils/date.ts (1)

77-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing explicit return type on public API.

formatDurationMs declares : string, but formatTimeInSeconds doesn't. As per coding guidelines, "Use explicit return types for public APIs and complex functions in TypeScript."

♻️ Proposed fix
-export const formatTimeInSeconds = (seconds?: number) => {
+export const formatTimeInSeconds = (seconds?: number): string => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/packages/common/src/utils/date.ts` at line 77, Update the public function
formatTimeInSeconds to declare its explicit return type as string, matching the
existing formatDurationMs API style and coding guidelines.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/packages/common/src/utils/date.ts`:
- Around line 77-81: Update formatTimeInSeconds to return an empty string when
seconds is less than 1, before applying Math.floor or calling formatDurationMs.
Preserve the existing empty handling for undefined and zero, and continue
formatting whole-second values unchanged.

---

Nitpick comments:
In `@web/packages/common/src/utils/date.test.ts`:
- Line 4: Update the date utility import in the test to use the repository’s
configured absolute alias path instead of the relative './date' path, while
preserving the existing imported symbols formatDurationMs, formatTimeInSeconds,
and utcToLocalDate.

In `@web/packages/common/src/utils/date.ts`:
- Line 77: Update the public function formatTimeInSeconds to declare its
explicit return type as string, matching the existing formatDurationMs API style
and coding guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f69f43ba-574f-4af6-b4bb-432bd645023a

📥 Commits

Reviewing files that changed from the base of the PR and between f952c03 and 0e700a6.

📒 Files selected for processing (7)
  • web/packages/common/src/utils/date.test.ts
  • web/packages/common/src/utils/date.ts
  • web/packages/studio/src/components/IntakeDetail/IntakeComponents/traceKeyValues.test.tsx
  • web/packages/studio/src/components/dataViews/ExperimentGroupDataView/index.tsx
  • web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx
  • web/packages/studio/src/routes/ExperimentDetailRoute/ExperimentDetailMetrics.tsx
  • web/packages/studio/src/util/intakeTelemetry.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/packages/studio/src/components/dataViews/ExperimentSessionsDataView/index.tsx
  • web/packages/studio/src/components/dataViews/ExperimentGroupDataView/index.tsx

Comment thread web/packages/common/src/utils/date.ts
rrhyne and others added 3 commits July 13, 2026 12:50
…ds sub-second empty

Address review:
- ExperimentDetailMetrics: remove the `!= null` guard before formatDurationMs.
  formatDurationMs already returns '—' for null/undefined, which is also KVPair's
  default empty value, so the guard was pure redundancy with identical output.
- formatTimeInSeconds: guard `seconds < 1` so fractional-second inputs render ''
  as before, instead of '0ms' (Math.floor(seconds) * 1000 collapsed to 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
…on-format/rrhyne

Signed-off-by: Rob Rhyne <rrhyne@nvidia.com>
@rrhyne
rrhyne enabled auto-merge July 14, 2026 16:26
@rrhyne
rrhyne added this pull request to the merge queue Jul 14, 2026
Merged via the queue into main with commit 14e8b0a Jul 14, 2026
55 checks passed
@rrhyne
rrhyne deleted the studio-latency-duration-format/rrhyne branch July 14, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants